﻿using System;
using System.Collections.Generic;

namespace Cms.Domain
{
    public class MenuItem : ICloneable, IComparable<MenuItem>, IEqualityComparer<MenuItem>
    {
        private Category _activeForPagesInCategory;
        private DateTime? _endPublishing;
        private int _id;
        private MenuItemLinkType _linkType;
        private MediaFile _mediaFile;
        private Page _page;
        private MenuItem _parent;
        private int _sortIndex;
        private DateTime? _startPublishing;
        private IList<MenuItem> _subItems;
        private string _target;
        private IDictionary<int, MenuItemTranslation> _translations;

        public MenuItem()
        {
            _subItems = new List<MenuItem>();
            _translations = new Dictionary<int, MenuItemTranslation>();
        }

        private MenuItem(MenuItem original)
            : this()
        {
            _linkType = original.LinkType;
            _endPublishing = original.EndPublishing;
            _mediaFile = original.MediaFile;
            _page = original.Page;
            _sortIndex = original.SortIndex;
            _startPublishing = original.StartPublishing;
            _target = original.Target;
            _activeForPagesInCategory = original.ActiveForPagesInCategory;
            foreach (var kvp in original.Translations)
            {
                _translations.Add(kvp.Key, (MenuItemTranslation)kvp.Value.Clone());
            }
        }

        public virtual int ID
        {
            get { return _id; }
            set { _id = value; }
        }

        public virtual int SortIndex
        {
            get { return _sortIndex; }
            set { _sortIndex = value; }
        }
        
        public virtual MenuVersion Version { get; set; }

        public virtual MenuItem Parent
        {
            get { return _parent; }
            set { _parent = value; }
        }
        
        public virtual IList<MenuItem> SubItems
        {
            get { return _subItems; }
            protected set { _subItems = value; }
        }
        
        public virtual DateTime? StartPublishing
        {
            get { return _startPublishing; }
            set { _startPublishing = value; }
        }
        
        public virtual DateTime? EndPublishing
        {
            get { return _endPublishing; }
            set { _endPublishing = value; }
        }
        
        public virtual IDictionary<int, MenuItemTranslation> Translations
        {
            get { return _translations; }
            set { _translations = value; }
        }

        public virtual MenuItemLinkType LinkType
        {
            get { return _linkType; }
            set { _linkType = value; }
        }
        
        public virtual Page Page
        {
            get { return _page; }
            set { _page = value; }
        }

        public virtual MediaFile MediaFile
        {
            get { return _mediaFile; }
            set { _mediaFile = value; }
        }

        public virtual string Target
        {
            get { return _target; }
            set { _target = value; }
        }

        public virtual Category ActiveForPagesInCategory
        {
            get { return _activeForPagesInCategory; }
            set { _activeForPagesInCategory = value; }
        }

        #region ICloneable Members

        public virtual object Clone()
        {
            return new MenuItem(this);
        }

        #endregion

        public virtual bool IsParentTo(MenuItem item)
        {
            if (item == null)
                return false;
            MenuItem parentItem = item.Parent;
            while (parentItem != null)
            {
                if (parentItem.ID == _id)
                    return true;
                parentItem = parentItem.Parent;
            }
            return false;
        }

        public virtual int GetLevelInTree()
        {
            int level = 0;
            MenuItem parent = _parent;
            while (parent != null)
            {
                parent = parent.Parent;
                level++;
            }
            return level;
        }

        public virtual MenuItemTranslation GetTranslation(int localeId)
        {
            return _translations.ContainsKey(localeId) ? _translations[localeId] : new MenuItemTranslation();
        }

        public virtual bool IsPublishedNow()
        {
            return
                !((_startPublishing.HasValue && _startPublishing.Value > DateTime.Now) ||
                  (_endPublishing.HasValue && _endPublishing.Value < DateTime.Now));
        }

        public virtual int CompareSortIndexTo(MenuItem other)
        {
            // Null is considered to be smaller than any other value.
            if (other == null)
                return 1;
            if (SortIndex < other.SortIndex)
                return -1;
            return SortIndex == other.SortIndex ? 0 : 1;
        }

        public virtual int CompareTo(MenuItem other)
        {
            return this.ID > 0 && this.ID == other.ID ? 0 : 1;
        }

        bool IEqualityComparer<MenuItem>.Equals(MenuItem x, MenuItem y)
        {
            if (x.ID != y.ID)
                return false;
            if (x.ID > 0 && x.ID == y.ID)
                return true;
            return ReferenceEquals(x, y);
        }

        int IEqualityComparer<MenuItem>.GetHashCode(MenuItem obj)
        {
            return obj.ID.GetHashCode();
        }
    }
}